package com.sample.livewallpaperdemo.widget;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.os.Handler;
import android.os.Looper;
import android.support.annotation.NonNull;
import android.view.MotionEvent;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.BounceInterpolator;
import android.widget.Toast;

import com.sample.livewallpaperdemo.R;

import org.rajawali3d.Object3D;
import org.rajawali3d.animation.Animation;
import org.rajawali3d.animation.Animation3D;
import org.rajawali3d.animation.AnimationQueue;
import org.rajawali3d.animation.IAnimationListener;
import org.rajawali3d.animation.RotateOnAxisAnimation;
import org.rajawali3d.materials.Material;
import org.rajawali3d.materials.methods.DiffuseMethod;
import org.rajawali3d.materials.textures.ATexture;
import org.rajawali3d.materials.textures.AlphaMapTexture;
import org.rajawali3d.materials.textures.Texture;
import org.rajawali3d.math.vector.Vector3;
import org.rajawali3d.primitives.Plane;
import org.rajawali3d.renderer.Renderer;
import org.rajawali3d.util.ObjectColorPicker;
import org.rajawali3d.util.OnObjectPickedListener;

/**
 * 天气时间widget
 */

public class TimeWeatherRenderer extends Renderer implements OnObjectPickedListener {

    // touch location
    private float mTouchX, mTouchY;

    private boolean mInAnimation = false;

    private ObjectColorPicker mPicker;
    private Object3D mGroup = new Object3D();
    private Plane mBg, mWeather, mTime, mTemperature;

    // time 是固定宽高，直接计算出来的
    private AlphaMapTexture mTimeTexture;
    private Bitmap mTimeBitmap;
    private Canvas mTimeCanvas;
    private volatile boolean mShouldUpdateTimeTexture;

    // temperature
    private AlphaMapTexture mTemperatureTexture;
    private Bitmap mTemperatureBitmap;
    private Canvas mTemperatureCanvas;
    private volatile boolean mShouldUpdateTemperatureTexture;

    public TimeWeatherRenderer(Context context) {
        super(context);
        init();
    }

    private void init() {
        // time
        Bitmap bitmap = TimeWeatherUtil.getBitmapByNumber(mContext, 1);
        int bitmapWidth = 4 * bitmap.getWidth()
                + TimeWeatherUtil.getBitmapByResId(mContext, R.drawable.time_num_link).getWidth();
        int bitmapHeight = bitmap.getHeight();
        mTimeBitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888);
        mTimeTexture = new AlphaMapTexture("timeTexture", mTimeBitmap);
        mTimeCanvas = new Canvas(mTimeBitmap);
        // tempeture
        bitmapWidth = 250;
        bitmapHeight = 200;
        mTemperatureBitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888);
        mTemperatureTexture = new AlphaMapTexture("temperatureTexture", mTemperatureBitmap);
        mTemperatureCanvas = new Canvas(mTemperatureBitmap);
    }

    @Override
    protected void initScene() {
        getCurrentScene().setBackgroundColor(Color.BLUE);

        addBackgroudObject();
        addWeatherObject();
        addTimeObject();
        addTemperatureObject();

        getCurrentScene().addChild(mGroup);

        // pick
        mPicker = new ObjectColorPicker(this);
        mPicker.setOnObjectPickedListener(this);
        mPicker.registerObject(mWeather);
        mPicker.registerObject(mTime);
        mPicker.registerObject(mTemperature);

        // move camera
        getCurrentCamera().enableLookAt();
        getCurrentCamera().setLookAt(0, 0, 0);
        getCurrentCamera().setZ(2);
    }

    private void addBackgroudObject() {
        Material material = new Material();
        try {
            material.addTexture(new Texture("time_weather_bg", R.drawable.checkerboard));
            material.setColorInfluence(0);
        } catch (ATexture.TextureException e) {
            e.printStackTrace();
        }

        mBg = new Plane(Vector3.Axis.Z);
        mBg.setMaterial(material);
        mBg.setDoubleSided(true);
        mBg.setZ(-0.2);
        mGroup.addChild(mBg);
    }

    private void addWeatherObject() {
        Material material = new Material();
        try {
            material.addTexture(new Texture("weather", R.drawable.rajawali_tex));
            material.setColorInfluence(0);
        } catch (ATexture.TextureException e) {
            e.printStackTrace();
        }

        mWeather = new Plane(Vector3.Axis.Z);
        mWeather.setMaterial(material);
        mWeather.setDoubleSided(true);
        mWeather.setZ(0);
        mGroup.addChild(mWeather);
    }

    private void addTimeObject() {
        Material timeSphereMaterial = new Material();
        timeSphereMaterial.enableLighting(true);
        timeSphereMaterial.setDiffuseMethod(new DiffuseMethod.Lambert());
        try {
            timeSphereMaterial.addTexture(mTimeTexture);
        } catch (ATexture.TextureException e) {
            e.printStackTrace();
        }
        timeSphereMaterial.setColorInfluence(1);

        float height = mTimeCanvas.getHeight() / (float) mTimeCanvas.getWidth();
        mTime = new Plane(1f, height, 1, 1);
        mTime.setMaterial(timeSphereMaterial);
        mTime.setColor(Color.GRAY);
        mTime.setDoubleSided(true);
        mTime.setScale(0.7f);
        mTime.setZ(0.2);
        mGroup.addChild(mTime);
    }

    private void addTemperatureObject() {
        Material temperatureSphereMaterial = new Material();
        temperatureSphereMaterial.enableLighting(true);
        temperatureSphereMaterial.setDiffuseMethod(new DiffuseMethod.Lambert());
        try {
            temperatureSphereMaterial.addTexture(mTemperatureTexture);
        } catch (ATexture.TextureException e) {
            e.printStackTrace();
        }
        temperatureSphereMaterial.setColorInfluence(1);

        float height = mTemperatureCanvas.getHeight() / (float) mTemperatureCanvas.getWidth();
        mTemperature = new Plane(1f, height, 1, 1);
        mTemperature.setMaterial(temperatureSphereMaterial);
        mTemperature.setColor(Color.RED);
        mTemperature.setDoubleSided(true);
        mTemperature.setY(0.4f);
        mTemperature.setZ(0.1);
        mGroup.addChild(mTemperature);
    }

    public Canvas getTimeCanvas() {
        return mTimeCanvas;
    }

    public Canvas getTemperatureCanvas() {
        return mTemperatureCanvas;
    }

    public void updateTimeCanvas() {
        //
        // -- Indicates that the texture should be updated on the OpenGL thread.
        //
        mShouldUpdateTimeTexture = true;
    }

    public void updateTemperatureCanvas() {
        //
        // -- Indicates that the texture should be updated on the OpenGL thread.
        //
        mShouldUpdateTemperatureTexture = true;
    }

    @Override
    public void onRender(final long elapsedTime, final double deltaTime) {
        //
        // -- update the texture because it is ready
        //
        if (mShouldUpdateTimeTexture) {
            mTimeTexture.setBitmap(mTimeBitmap);
            mTextureManager.replaceTexture(mTimeTexture);
            mShouldUpdateTimeTexture = false;
        }
        if (mShouldUpdateTemperatureTexture) {
            mTemperatureTexture.setBitmap(mTemperatureBitmap);
            mTextureManager.replaceTexture(mTemperatureTexture);
            mShouldUpdateTemperatureTexture = false;
        }
        super.onRender(elapsedTime, deltaTime);
    }

    @Override
    public void onTouchEvent(MotionEvent event) {
    }

    public void onOffsetsChanged(float x, float y, float z, float w, int i, int j){
    }

    public void pickObjectAt(float x, float y) {
        mTouchX = x;
        mTouchY = y;
        mPicker.getObjectAt(x, y);
    }

    @Override
    public void onObjectPicked(@NonNull Object3D object) {
        if (object == mTime) {
            Handler handler = new Handler(Looper.getMainLooper());
            handler.post(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(mContext, "Time object selected!", Toast.LENGTH_SHORT).show();
                }
            });
        } else if (object == mWeather || object == mTemperature) {
            doClickAnimation();
        }
    }

    @Override
    public void onNoObjectPicked() {
        // Ignore
    }

    private void doClickAnimation() {
        if (mInAnimation) {
            return;
        }
        if (mSurface != null && mSurface instanceof TimeWeatherTextureView) {
            mInAnimation = true;
            TimeWeatherTextureView textureView = (TimeWeatherTextureView) mSurface;
            int centerX = textureView.getWidth() / 2;
            int centerY = textureView.getHeight() / 2;
            int deltaX = (int) mTouchX - centerX;
            int deltaY = (int) mTouchY - centerY;

            float axisX = deltaY;
            float axisY = deltaX;
            float degreesToRotate = 40f;

            // do animation
            AnimationQueue queue = new AnimationQueue();

            Animation3D anim1 = new RotateOnAxisAnimation(new Vector3(axisX, axisY, 0), -degreesToRotate);
            anim1.setDurationMilliseconds(500);
            anim1.setTransformable3D(mGroup);
            anim1.setInterpolator(new AccelerateInterpolator());

            Animation3D anim2 = new RotateOnAxisAnimation(new Vector3(axisX, axisY, 0), degreesToRotate);
            anim2.setDurationMilliseconds(2000);
            anim2.setTransformable3D(mGroup);
            anim2.setInterpolator(new BounceInterpolator());

            queue.addAnimation(anim1);
            queue.addAnimation(anim2);

            queue.registerListener(new IAnimationListener() {
                @Override
                public void onAnimationEnd(Animation animation) {
                    mInAnimation = false;
                }

                @Override
                public void onAnimationRepeat(Animation animation) {

                }

                @Override
                public void onAnimationStart(Animation animation) {

                }

                @Override
                public void onAnimationUpdate(Animation animation, double interpolatedTime) {

                }
            });

            getCurrentScene().registerAnimation(queue);
            queue.play();
        }
    }
}
